home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / cpicker / cpicker.c < prev    next >
C/C++ Source or Header  |  1995-06-22  |  25KB  |  936 lines

  1. /*
  2.  * cpicker.c - Colormap editor for X11
  3.  * 
  4.  * Author:    Mike Yang (mikey@sgi.com)
  5.  *        Silicon Graphics, Inc.
  6.  * Date:    Mon Jul 29 1991
  7.  * Copyright (c) 1988, 1991 Mike Yang
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <math.h>
  12. #include "Cpick.h"
  13. #include <X11/Xproto.h>
  14. #include <X11/cursorfont.h>
  15. #include <Xm/Form.h>
  16. #include <Xm/MessageB.h>
  17.  
  18. #define HELP_STRING    "Cpicker, a colormap editing utility.  Mike Yang, Silicon Graphics, mikey@sgi.com"
  19.  
  20. /* #define USE_COLORS    /* define to make the scale labels colored */
  21.  
  22. /* We do this because most servers support only the upper 8 bits for RGB */
  23. #define SAME_COLOR(x,y)    ((x)/256 == (y)/256 || (x)/256+1 == (y)/256 || (x)/256 == (y)/256+1)
  24.  
  25. XColor allocated, current;
  26. Widget glevel, toplevel, cpick, dialog;
  27. XColor mapv[MAXPIXELS];
  28. Colormap cmap;
  29. Boolean picking = TRUE;
  30. int maxpixels, numpixels, numfree, realfree;
  31. Position choose_x = 200, choose_y = 200;
  32. unsigned long avail[MAXPIXELS], got[MAXPIXELS];
  33. Window win;
  34. XmColorProc colorProc;
  35. XColor fgColor, selectColor, topColor, bottomColor;
  36. Boolean doMotif, haveFg, haveSelect, haveTop, haveBottom;
  37.  
  38. typedef unsigned long (*PixProc)();
  39.  
  40. struct vals {
  41.   int ih, iw, x0, y0, rownum;
  42.   PixProc pix;
  43. } gval, nval;
  44.  
  45. Arg gargs[] = {
  46.   {XmNborderColor, NULL},
  47.   {XmNheight, 1},
  48.   {XmNwidth, 1},
  49.   {XmNtopAttachment, XmATTACH_FORM},
  50.   {XmNbottomAttachment, XmATTACH_FORM},
  51.   {XmNleftAttachment, XmATTACH_FORM},
  52.   {XmNrightAttachment, XmATTACH_FORM},
  53. };
  54.  
  55. Arg setargs[] = {
  56.   {XmNallocated, (XtArgVal) &allocated},
  57. };
  58.  
  59. static XrmOptionDescRec cmdOptions[] = {
  60.   {
  61.     "-motif", ".motif", XrmoptionIsArg, NULL,
  62.   },
  63.   {
  64.     "-noMotif", ".noMotif", XrmoptionIsArg, NULL,
  65.   },
  66.   {
  67.     "-nomotif", ".noMotif", XrmoptionIsArg, NULL,
  68.   },
  69. };
  70.  
  71. static Arg args[20];
  72. static int count;
  73.  
  74. usage()
  75. {
  76.     fprintf (stderr,
  77.         "usage:  cpicker [-options ...]\n\n");
  78.     fprintf (stderr,
  79.         "where options include:\n");
  80.     fprintf (stderr,
  81.         "    -display host:dpy    X server to contact\n");
  82.     fprintf (stderr,
  83.         "    -root                use the root window\n");
  84.     fprintf (stderr,
  85.         "    -id windowid         use the window with the specified id\n");
  86.     fprintf (stderr,
  87.         "    -wname windowname    use the window with the specified name\n");
  88.     fprintf (stderr,
  89.     "    -motif               enable Motif color matching (the default)\n");
  90.     fprintf (stderr,
  91.     "    -noMotif             disable Motif color matching\n");
  92. }
  93.  
  94. /*
  95.  * (code taken from xwininfo)
  96.  *
  97.  * Standard fatal error routine - call like printf but maximum of 7 arguments.
  98.  * Does not require dpy or screen defined.
  99.  */
  100. void Fatal_Error(msg, arg0,arg1,arg2,arg3,arg4,arg5,arg6)
  101. char *msg;
  102. char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
  103. {
  104.         fflush(stdout);
  105.         fflush(stderr);
  106.         fprintf(stderr, "cpicker: error: ");
  107.         fprintf(stderr, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
  108.         fprintf(stderr, "\n");
  109.         exit(1);
  110. }
  111.  
  112. /*
  113.  * (code taken from xwininfo)
  114.  *
  115.  * Window_With_Name: routine to locate a window with a given name on a display.
  116.  *                   If no window with the given name is found, 0 is returned.
  117.  *                   If more than one window has the given name, the first
  118.  *                   one found will be returned.  Only top and its subwindows
  119.  *                   are looked at.  Normally, top should be the RootWindow.
  120.  */
  121. Window Window_With_Name(dpy, top, name)
  122.      Display *dpy;
  123.      Window top;
  124.      char *name;
  125. {
  126.     Window *children, dummy;
  127.     unsigned int nchildren, i;
  128.     Window w=0;
  129.     char *window_name;
  130.  
  131.     if (XFetchName(dpy, top, &window_name) && !strcmp(window_name, name))
  132.       return(top);
  133.  
  134.     if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren))
  135.       return(0);
  136.  
  137.     for (i=0; i<nchildren; i++) {
  138.         w = Window_With_Name(dpy, children[i], name);
  139.         if (w)
  140.           break;
  141.     }
  142.     XFree((char *) children);
  143.     return(w);
  144. }
  145.  
  146. /*
  147.  * (code taken from xwininfo)
  148.  *
  149.  * Select_Window_Args: a rountine to provide a common interface for
  150.  *                     applications that need to allow the user to select one
  151.  *                     window on the screen for special consideration.
  152.  *                     This routine implements the following command line
  153.  *                     arguments:
  154.  *
  155.  *                       -root            Selects the root window.
  156.  *                       -id <id>         Selects window with id <id>. <id> may
  157.  *                                        be either in decimal or hex.
  158.  *                       -wname <name>     Selects the window with name <name>.
  159.  *
  160.  *                     Call as Select_Window_Args(&argc, argv) in main before
  161.  *                     parsing any of your program's command line arguments.
  162.  *                     Select_Window_Args will remove its arguments so that
  163.  *                     your program does not have to worry about them.
  164.  *                     The window returned is the window selected or 0 if
  165.  *                     none of the above arguments was present.  If 0 is
  166.  *                     returned, Select_Window should probably be called after
  167.  *                     all command line arguments, and other setup is done.
  168.  *                     For examples of usage, see xwininfo, xwd, or xprop.
  169.  */
  170. Window Select_Window_Args(rargc, argv)
  171.      int *rargc;
  172.      char **argv;
  173. #define ARGC (*rargc)
  174. {
  175.     int nargc=1;
  176.     int argc;
  177.     char **nargv;
  178.     Window w=0;
  179.     Display *dpy;
  180.     int screen;
  181.  
  182.     nargv = argv+1; argc = ARGC;
  183. #define OPTION argv[0]
  184. #define NXTOPTP ++argv, --argc>0
  185. #define NXTOPT if (++argv, --argc==0) usage()
  186. #define COPYOPT nargv++[0]=OPTION; nargc++
  187.  
  188.     dpy =  XtDisplay(toplevel);
  189.     screen =  XDefaultScreen(XtDisplay(toplevel));
  190.  
  191.     while (NXTOPTP) {
  192.         if (!strcmp(OPTION, "-")) {
  193.             COPYOPT;
  194.             while (NXTOPTP)
  195.               COPYOPT;
  196.             break;
  197.         }
  198.         if (!strcmp(OPTION, "-root")) {
  199.             w=RootWindow(dpy, screen);
  200.             continue;
  201.         }
  202.         if (!strcmp(OPTION, "-wname")) {
  203.             NXTOPT;
  204.             w = Window_With_Name(dpy, RootWindow(dpy, screen),
  205.                          OPTION);
  206.             if (!w)
  207.               Fatal_Error("No window with name %s exists!",OPTION);
  208.             continue;
  209.         }
  210.         if (!strcmp(OPTION, "-id")) {
  211.             NXTOPT;
  212.             w=0;
  213.             sscanf(OPTION, "0x%lx", &w);
  214.             if (!w)
  215.               sscanf(OPTION, "%ld", &w);
  216.             if (!w)
  217.               Fatal_Error("Invalid window id format: %s.", OPTION);
  218.             continue;
  219.         }
  220.         COPYOPT;
  221.     }
  222.     ARGC = nargc;
  223.     
  224.     return(w);
  225. }
  226.  
  227. void postDialog(msg)
  228. char *msg;
  229. {
  230.   XmString xs;
  231.  
  232.   xs = XmStringCreateSimple(msg);
  233.   count = 0;
  234.   XtSetArg(args[count], XmNmessageString, xs);  count++;
  235.   XtSetValues(dialog, args, count);
  236.   XtManageChild(dialog);
  237. }
  238.  
  239. Dimension getD(w, s)
  240. Widget w;
  241. String s;
  242. {
  243.   Dimension result;
  244.   Arg args[1];
  245.   int v;
  246.  
  247.   XtSetArg(args[0],s,(XtArgVal) &result);
  248.   XtGetValues(w, args, XtNumber(args));
  249.   v = result;
  250.  
  251.   return(v);
  252. }
  253.  
  254. Position getP(w, s)
  255. Widget w;
  256. String s;
  257. {
  258.   Position result;
  259.   Arg args[1];
  260.   int v;
  261.  
  262.   XtSetArg(args[0],s,(XtArgVal) &result);
  263.   XtGetValues(w, args, XtNumber(args));
  264.   v = result;
  265.  
  266.   return(v);
  267. }
  268.  
  269. gButtonHandler(w, val, event)
  270. Widget w;
  271. struct vals *val;
  272. XButtonEvent *event;
  273. {
  274.   int newpix, each, each2;
  275.   Widget bframe;
  276.   XColor bgColor;
  277.  
  278.   picking = TRUE;
  279.   newpix = val->pix((event->x-val->x0)/val->iw +
  280.             ((event->y-val->y0)/val->ih)*val->rownum);
  281.   for (each=0; each<=realfree; each++) {
  282.     if (newpix == avail[each]) {
  283.       postDialog("That's one of the widget's colormap cells.  Pick another.");
  284.       XBell(XtDisplay(w), 0);
  285.       return;
  286.     }
  287.   }
  288.   if (newpix < numpixels) {
  289.     XtUnmapWidget(w);
  290.     current.pixel = newpix;
  291.     /* generates error if can't allocate */
  292.     XQueryColor(XtDisplay(toplevel), cmap, ¤t);
  293.     allocated.red = current.red;
  294.     allocated.green = current.green;
  295.     allocated.blue = current.blue;
  296.     XSync(XtDisplay(toplevel), 0);
  297.     if (picking) {
  298.       /* generates error if can't allocate */
  299.       XStoreColor(XtDisplay(toplevel), cmap, ¤t);
  300.       XSync(XtDisplay(toplevel), 0);
  301.       if (picking) {
  302.     XtSetValues(cpick, setargs, XtNumber(setargs));
  303.     XtUnmanageChild(dialog);
  304.     XtMapWidget(cpick);
  305.     if (doMotif) {
  306.       bgColor.pixel = current.pixel;
  307.       bgColor.red = mapv[current.pixel].red;
  308.       bgColor.green = mapv[current.pixel].green;
  309.       bgColor.blue = mapv[current.pixel].blue;
  310.       (*colorProc)(&bgColor, &fgColor, &selectColor, &topColor,
  311.                &bottomColor);
  312.       for (each=0; each<numpixels; each++) {
  313.         for (each2=0; each2<=realfree; each2++) {
  314.           if (mapv[each].pixel == avail[each2]) {
  315.         break;
  316.           }
  317.         }
  318.         if (each2 > realfree) {
  319.           if (!haveFg &&
  320.           SAME_COLOR(mapv[each].red, fgColor.red) &&
  321.           SAME_COLOR(mapv[each].green, fgColor.green) &&
  322.           SAME_COLOR(mapv[each].blue, fgColor.blue)) {
  323.         fgColor.pixel = mapv[each].pixel;
  324. /* Don't know what this color is used for
  325.                haveFg = True;
  326. */
  327.           } else if (!haveSelect &&
  328.              SAME_COLOR(mapv[each].red, selectColor.red) &&
  329.              SAME_COLOR(mapv[each].green, selectColor.green) &&
  330.              SAME_COLOR(mapv[each].blue, selectColor.blue)) {
  331.         selectColor.pixel = mapv[each].pixel;
  332. /* Don't know what this color is used for
  333.         haveSelect = True;
  334. */
  335.           } else if (!haveTop &&
  336.              SAME_COLOR(mapv[each].red, topColor.red) &&
  337.              SAME_COLOR(mapv[each].green, topColor.green) &&
  338.              SAME_COLOR(mapv[each].blue, topColor.blue)) {
  339.         topColor.pixel = mapv[each].pixel;
  340.         haveTop = True;    
  341.           } else if (!haveBottom &&
  342.              SAME_COLOR(mapv[each].red, bottomColor.red) &&
  343.              SAME_COLOR(mapv[each].green, bottomColor.green) &&
  344.              SAME_COLOR(mapv[each].blue, bottomColor.blue)) {
  345.         bottomColor.pixel = mapv[each].pixel;
  346.         haveBottom = True;
  347.           }
  348.         }
  349.       }
  350.     }
  351.     bframe = CpickGetBoxFrame(cpick);
  352.     count = 0;
  353.     if (haveTop) {
  354.       XtSetArg(args[count], XmNtopShadowColor, topColor.pixel);  count++;
  355.       XtSetArg(args[count], XmNtopShadowPixmap,
  356.            XmUNSPECIFIED_PIXMAP);  count++;
  357.     } else {
  358.       XtSetArg(args[count], XmNtopShadowColor, current.pixel);  count++;
  359.       XtSetArg(args[count], XmNtopShadowPixmap,
  360.            XmUNSPECIFIED_PIXMAP);  count++;
  361.     }
  362.     if (haveBottom) {
  363.       XtSetArg(args[count], XmNbottomShadowColor,
  364.            bottomColor.pixel);  count++;
  365.       XtSetArg(args[count], XmNbottomShadowPixmap,
  366.            XmUNSPECIFIED_PIXMAP);  count++;
  367.     } else {
  368.       XtSetArg(args[count], XmNbottomShadowColor,
  369.            current.pixel);  count++;
  370.       XtSetArg(args[count], XmNbottomShadowPixmap,
  371.            XmUNSPECIFIED_PIXMAP);  count++;
  372.     }
  373.     XtSetValues(bframe, args, count);
  374.       } else {
  375.     XBell(XtDisplay(w), 0);
  376.     XtMapWidget(w);
  377.       }
  378.     } else {
  379.       XtMapWidget(w);
  380.     }
  381.   } else {
  382.     postDialog("Can't allocate that colormap cell.  Pick another.");
  383.     XBell(XtDisplay(w), 0);
  384.   }
  385. }
  386.  
  387. createGrid(wid, num, max, x0, y0, h, w, proc, val, pix)
  388. Widget wid;
  389. int num, max;
  390. Position x0, y0;
  391. Dimension h, w;
  392. XtEventHandler proc;
  393. struct vals *val;
  394. PixProc pix;
  395. {
  396.   int each, x, y, hs, ws;
  397.   double hsize, wsize;
  398.   GC gc;
  399.   XGCValues gcv;
  400.   unsigned long black;
  401.  
  402.   val->pix = pix;
  403.  
  404.   wsize = sqrt((double) max);
  405.   hsize = wsize;
  406.   val->ih = (int) ((h-1)/hsize);
  407.   val->iw = (int) ((w-1)/wsize);
  408.   val->rownum = (int) wsize;
  409.   hs = (int) hsize*val->ih+1;
  410.   ws = (int) wsize*val->iw+1;
  411.  
  412.   XtMoveWidget(wid, x0, y0);
  413.   XtResizeWidget(wid, w, h, (Dimension) 1);
  414.  
  415.   val->y0 = (h-hs)/2;
  416.   val->x0 = (w-ws)/2;
  417.  
  418.   gcv.function = GXcopy;
  419.   gcv.fill_style = FillSolid;
  420.   black = XBlackPixel(XtDisplay(wid),
  421.               XDefaultScreen(XtDisplay(wid)));
  422.   gcv.background = black;
  423.   gc = XCreateGC(XtDisplay(wid), XtWindow(wid),
  424.          GCBackground | GCFunction | GCFillStyle, &gcv);
  425.  
  426.   XSync(XtDisplay(wid),0);
  427.   for (each=0; each<num; each++) {
  428.     x = (each % val->rownum)*val->iw;
  429.     y = (each/val->rownum)*val->ih;
  430.     XSetForeground(XtDisplay(wid), gc, pix(each));
  431.     XFillRectangle(XtDisplay(wid), XtWindow(wid), gc, val->x0+x, val->y0+y,
  432.            val->iw, val->ih);
  433.     XSetForeground(XtDisplay(wid), gc, black);
  434.     XDrawRectangle(XtDisplay(wid), XtWindow(wid), gc, val->x0+x, val->y0+y,
  435.            val->iw, val->ih);
  436.   }
  437.  
  438.   XtAddEventHandler(wid, ButtonPressMask, FALSE, (XtEventHandler) proc,
  439.             (XtPointer) val);
  440.   XFreeGC(XtDisplay(wid), gc);
  441. }
  442.  
  443. unsigned long gPixel(each)
  444. int each;
  445. {
  446.   return each;
  447. }
  448.  
  449. Boolean
  450. ExposePending(display, event, arg)
  451. Display *display;
  452. XEvent *event;
  453. Widget arg;
  454. {
  455.   return((event->type == Expose) &&
  456.      (((XExposeEvent *)event)->window == XtWindow(arg)));
  457. }
  458.  
  459. doExpose()
  460. {
  461.   createGrid(glevel, numpixels, maxpixels, (Position) 0, (Position) 0,
  462.          getD(toplevel, XmNheight),
  463.          getD(toplevel, XmNwidth),
  464.          gButtonHandler, &gval, gPixel);
  465. }
  466.  
  467. exposeHandler(w, client_data, event)
  468. Widget w;
  469. XtPointer client_data;
  470. XEvent *event;
  471. {
  472.   XEvent ev;
  473.  
  474. /*
  475.   XFlush(XtDisplay(w));
  476.   while (XCheckIfEvent(XtDisplay(toplevel), &ev, ExposePending, w)) {
  477.   }
  478. */
  479.   
  480.   if (((XExposeEvent *)event)->count == 0) {
  481.     doExpose();
  482.   }
  483. }
  484.  
  485. resizeHandler(w, client_data, event)
  486. Widget w;
  487. XtPointer client_data;
  488. XEvent *event;
  489. {
  490.   if (event->type == ConfigureNotify) {
  491.     XClearWindow(XtDisplay(w), XtWindow(w));
  492.     createGrid(glevel, numpixels, maxpixels, (Position) 0, (Position) 0,
  493.            getD(toplevel, XmNheight),
  494.            getD(toplevel, XmNwidth),
  495.            gButtonHandler, &gval, gPixel);
  496.   }
  497. }
  498.  
  499. saveCurrent()
  500. {
  501.   current.red = allocated.red;
  502.   current.green = allocated.green;
  503.   current.blue = allocated.blue;
  504.   XStoreColor(XtDisplay(toplevel), cmap, ¤t);
  505. }
  506.  
  507. restoreCmap()
  508. {
  509.   Display *dpy;
  510.   int each, each2, count;
  511.   Boolean found;
  512.   XColor copy[MAXPIXELS];
  513.  
  514.   dpy = XtDisplay(toplevel);
  515.  
  516.   count = 0;
  517.   for (each=0; each<numpixels; each++) {
  518.     found = FALSE;
  519.     for (each2=0; (each2<=realfree) && !found; each2++) {
  520.       if (avail[each2] == got[each])
  521.     found = TRUE;
  522.     }
  523.     if (!found)
  524.       copy[count++] = mapv[got[each]];
  525.   }
  526.  
  527.   XStoreColors(dpy,cmap,copy,count);
  528. /*
  529.   XInstallColormap(dpy,cmap);
  530.  
  531.   XStoreColors(dpy,cmap,copy,count);
  532.   XInstallColormap(dpy,cmap);
  533. */
  534. }
  535.  
  536. doSelect(cmd, cdata, position)
  537.      Widget cmd;
  538.      XtPointer cdata;
  539.      float position;
  540. {
  541.   XtMapWidget(glevel);
  542.   XtUnmapWidget(cpick);
  543. }
  544.  
  545. doOk(cmd, cdata, position)
  546.      Widget cmd;
  547.      XtPointer cdata;
  548.      float position;
  549. {
  550.   restoreCmap();
  551.   exit(0);
  552. }
  553.  
  554. doHelp(cmd, cdata, position)
  555.      Widget cmd;
  556.      XtPointer cdata;
  557.      float position;
  558. {
  559.   static Widget info = NULL;
  560.   XmString title, message;
  561.  
  562.   if (!info) {
  563.     count = 0;
  564.     title = XmStringCreateSimple("Cpicker Help");
  565.     XtSetArg(args[count], XmNdialogTitle, title);  count++;
  566.     message = XmStringCreateSimple(HELP_STRING);
  567.     XtSetArg(args[count], XmNmessageString, message);  count++;
  568.     info = XmCreateInformationDialog(toplevel, "info", args, count);
  569.     XtUnmanageChild(XmMessageBoxGetChild(info, XmDIALOG_CANCEL_BUTTON));
  570.     XtUnmanageChild(XmMessageBoxGetChild(info, XmDIALOG_HELP_BUTTON));
  571.     XmStringFree(title);
  572.     XmStringFree(message);
  573.   }
  574.   XtManageChild(info);
  575. }
  576.  
  577. doChange(cmd, cdata, position)
  578.      Widget cmd;
  579.      XtPointer cdata;
  580.      float position;
  581. {
  582.   saveCurrent();
  583.   if (haveFg || haveSelect || haveTop || haveBottom) {
  584.     XColor bgColor;
  585.  
  586.     bgColor.pixel = current.pixel;
  587.     bgColor.red = current.red;
  588.     bgColor.green = current.green;
  589.     bgColor.blue = current.blue;
  590.     (*colorProc)(&bgColor, &fgColor, &selectColor, &topColor, &bottomColor);
  591.     if (haveFg) {
  592.       XStoreColor(XtDisplay(toplevel), cmap, &fgColor);
  593.     }
  594.     if (haveSelect) {
  595.       XStoreColor(XtDisplay(toplevel), cmap, &selectColor);
  596.     }
  597.     if (haveTop) {
  598.       XStoreColor(XtDisplay(toplevel), cmap, &topColor);
  599.     }
  600.     if (haveBottom) {
  601.       XStoreColor(XtDisplay(toplevel), cmap, &bottomColor);
  602.     }
  603.   }
  604. }
  605.  
  606. doRestore(cmd, cdata, position)
  607.      Widget cmd;
  608.      XtPointer cdata;
  609.      float position;
  610. {
  611.   restoreCmap();
  612.   XQueryColor(XtDisplay(toplevel), cmap, ¤t);
  613.   allocated.red = current.red;
  614.   allocated.green = current.green;
  615.   allocated.blue = current.blue;
  616.   XtSetValues(cpick, setargs, XtNumber(setargs));
  617. }
  618.  
  619. int createCmap(num, wcmap, visual)
  620. int num;
  621. Colormap wcmap;
  622. Visual *visual;
  623. {
  624.   Display *dpy;
  625.   int screen, each, real;
  626.  
  627.   real = num+1;
  628.  
  629.   dpy = XtDisplay(toplevel);
  630.   screen = XDefaultScreen(XtDisplay(toplevel));
  631.  
  632.   for (each=0; each<maxpixels; each++) {
  633.     mapv[each].pixel = each;
  634.     mapv[each].flags = (DoRed | DoGreen | DoBlue);
  635.   }
  636.   XQueryColors(dpy, wcmap, mapv, numpixels);
  637.  
  638.   while ((real > 1) &&
  639.      (!XAllocColorCells(dpy, wcmap, FALSE, NULL, 0, avail,
  640.                 real+1))) {
  641.     real--;
  642.   }
  643.  
  644.   if (real <= 1) {
  645.     fprintf(stderr, "Sorry, can't allocate enuf colormap cells.\n");
  646.     exit(1);
  647.   }
  648.  
  649.   cmap = XCreateColormap(dpy, XRootWindow(dpy,screen),
  650.              visual, AllocNone);
  651.  
  652.   XAllocColorCells(dpy, cmap, FALSE, NULL, 0, got, numpixels);
  653.   XStoreColors(dpy,cmap,mapv,numpixels);
  654.   XFreeColors(dpy, cmap, avail, real, 0);
  655.   allocated = mapv[avail[real]];
  656.  
  657.   XInstallColormap(dpy,cmap);
  658.  
  659.   return real-1;
  660. }
  661.  
  662. errorHandler(dpy, event)
  663. Display *dpy;
  664. XErrorEvent *event;
  665. {
  666.   char buf[256];
  667.  
  668.   if ((event->error_code == BadAccess) ||
  669.       (event->request_code == X_QueryColors)) {
  670.     postDialog("Can't allocate that colormap cell.  Pick another.");
  671.     XBell(dpy, 0);
  672.     picking = FALSE;
  673.   } else {
  674.     XGetErrorText(dpy, event->error_code, buf, 256);
  675.     fprintf(stderr, "X protocol error detected by server: %s\n", buf);
  676.     fprintf(stderr, "  Failed request major op code %d\n", (int) event->request_code);
  677.     exit(1);
  678.   }
  679. }
  680.  
  681. Window chooseWindow(dpy)
  682. Display *dpy;
  683. {
  684.   Window chosen, last, ignorew;
  685.   int ignore;
  686.   unsigned int ignoreu;
  687.   XEvent ev;
  688.  
  689.   XGrabPointer(XtDisplay(toplevel),
  690.            XRootWindowOfScreen(XDefaultScreenOfDisplay(XtDisplay(toplevel))),
  691.            FALSE,
  692.            ButtonPressMask,
  693.            GrabModeAsync,
  694.            GrabModeSync,
  695.            None,
  696.            XCreateFontCursor(XtDisplay(toplevel), XC_crosshair),
  697.            CurrentTime);
  698.  
  699.   while (True) {
  700.     XtAppNextEvent(XtWidgetToApplicationContext(toplevel), &ev);
  701.     if (ev.type == ButtonPress) {
  702.       break;
  703.     } else {
  704.       XtDispatchEvent(&ev);
  705.     }
  706.   }
  707.  
  708.   last = XDefaultRootWindow(XtDisplay(toplevel));
  709.   chosen = last;
  710.   while (chosen != None) {
  711.     XQueryPointer(XtDisplay(toplevel), last,  &ignorew, &chosen,
  712.           &ignore, &ignore, &ignore, &ignore, &ignoreu);
  713.     if (chosen != None)
  714.       last = chosen;
  715.   }
  716.   XUngrabPointer(XtDisplay(toplevel), CurrentTime);
  717.   choose_x = ev.xbutton.x;
  718.   choose_y = ev.xbutton.y;
  719.   return last;
  720. }
  721.  
  722. main(argc, argv)
  723.     int argc;
  724.     char **argv;
  725. {
  726.   Widget realtop;
  727.   int nvi, i;
  728.   Dimension cw, ch;
  729.   Position x, y;
  730.   Boolean found;
  731.   XVisualInfo *vip, viproto, *bestvip;
  732.   XWindowAttributes xwa;
  733.   XmString title;
  734.  
  735.   static Arg mainargs[] = {
  736.     {XmNcmap, NULL},
  737. #ifdef USE_COLORS
  738.     {XmNuseColors, TRUE},
  739. #else
  740.     {XmNuseColors, FALSE},
  741. #endif
  742.     {XmNnearPixels, NULL},
  743.     {XmNallocated, (XtArgVal) &allocated},
  744.     {XmNtopAttachment, XmATTACH_FORM},
  745.     {XmNbottomAttachment, XmATTACH_FORM},
  746.     {XmNleftAttachment, XmATTACH_FORM},
  747.     {XmNrightAttachment, XmATTACH_FORM},
  748.     {XmNokLabel, (XtArgVal) "Quit"},
  749.     {XmNborderWidth, (XtArgVal) 0},
  750.   };
  751.   
  752.   allocated.flags = current.flags = DoRed | DoGreen | DoBlue;
  753.   
  754.   realtop = XtInitialize(argv[0], "Cpicker", cmdOptions, XtNumber(cmdOptions),
  755.              &argc, argv);
  756.  
  757. #ifdef USE_SCHEMES
  758.   VkLoadScheme(XtDisplay(realtop), argv[0], "Pixedit");
  759. #endif
  760.  
  761.   count = 0;
  762.   toplevel = XmCreateForm(realtop, "form", args, count);
  763.   XtManageChild(toplevel);
  764.   
  765.   if (XDisplayPlanes(XtDisplay(toplevel),
  766.              XDefaultScreen(XtDisplay(toplevel))) == 1) {
  767.     fprintf(stderr, "Sorry, you need a color display.\n");
  768.     exit(1);
  769.   }
  770.  
  771.   XSetErrorHandler(errorHandler);
  772.  
  773.   doMotif = (XGetDefault(XtDisplay(toplevel), argv[0], "noMotif") == NULL);
  774.   if (doMotif) {
  775.     colorProc = XmGetColorCalculation();
  776.     fgColor.flags = selectColor.flags = topColor.flags = bottomColor.flags =
  777.       DoRed | DoGreen | DoBlue;
  778.   }
  779.  
  780.   count = 0;
  781.   title = XmStringCreateSimple("Cpicker");
  782.   XtSetArg(args[count], XmNdialogTitle, title);  count++;
  783.   dialog = XmCreateMessageDialog(toplevel, "dialog", args, count);
  784.   XmStringFree(title);
  785.   XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_DEFAULT_BUTTON));
  786.   XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
  787.   XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
  788.  
  789.   found = FALSE;
  790.   if (win = Select_Window_Args(&argc, argv)) {
  791.     XGetWindowAttributes(XtDisplay(toplevel), win, &xwa);
  792.     viproto.visual = xwa.visual;
  793.     viproto.class = PseudoColor;
  794.     vip = XGetVisualInfo(XtDisplay(toplevel), VisualClassMask, &viproto, &nvi);
  795.     if (nvi && xwa.colormap) {
  796.       found = TRUE;
  797.     } else {
  798.       postDialog("Sorry, that window doesn't have a colormap to edit (no PseudoColor visual).  Pick another.");
  799.       XBell(XtDisplay(toplevel), 0);
  800.     }
  801.   } else {
  802.     if (argc != 1) {
  803.       usage();
  804.       exit(1);
  805.     }
  806.     postDialog("Click on a window to edit its colormap.");
  807.   }    
  808.  
  809.   while (!found) {
  810.     win = chooseWindow(XtDisplay(toplevel));
  811.     XGetWindowAttributes(XtDisplay(toplevel), win, &xwa);
  812.     viproto.visual = xwa.visual;
  813.     viproto.class = PseudoColor;
  814.     vip = XGetVisualInfo(XtDisplay(toplevel), VisualClassMask, &viproto, &nvi);
  815.     if (nvi && xwa.colormap) {
  816.       found = TRUE;
  817.     } else {
  818.       postDialog("Sorry, that window doesn't have a colormap to edit (no PseudoColor visual).  Pick another.");
  819.       XBell(XtDisplay(toplevel), 0);
  820.     }
  821.   }
  822.  
  823. /* First try to find a visual that matches the selected window's visual */
  824.   bestvip = (XVisualInfo *) NULL;
  825.   for (i=0; i<nvi; i++) {
  826.     if (xwa.visual == vip[i].visual) {
  827.       bestvip = vip+i;
  828.     }
  829.   }
  830. /* Otherwise, find the pseudocolor visual with the most colormap entries,
  831.    but within our hardcoded limit */
  832.   if (!bestvip || bestvip->colormap_size > MAXPIXELS) {
  833.     bestvip = vip;
  834.     for (i=1; i<nvi; i++) {
  835.       if (bestvip->colormap_size < vip[i].colormap_size &&
  836.       vip[i].colormap_size <= MAXPIXELS) {
  837.     bestvip = vip+i;
  838.       }
  839.     }
  840.   }
  841.   numpixels = bestvip->colormap_size;
  842.   maxpixels = 1;
  843.   while (maxpixels < numpixels) {
  844.     maxpixels = maxpixels*2;
  845.   }
  846.  
  847.   if (numpixels < 11) {
  848.     fprintf(stderr, "Sorry, you don't have enough colormap cells.\n");
  849.     exit(1);
  850.   } else if (numpixels < 58) {
  851.     mainargs[1].value = (XtArgVal) FALSE;
  852.     mainargs[2].value = (XtArgVal) 4;
  853.     numfree = COLORLESSPIXELS+4;
  854.   } else if (numpixels < 136) {
  855. #ifdef USE_COLORS
  856.       mainargs[1].value = (XtArgVal) TRUE;
  857.       mainargs[2].value = (XtArgVal) 25;
  858.       numfree = NECESSARYPIXELS+25;
  859. #else
  860.       mainargs[1].value = (XtArgVal) FALSE;
  861.       mainargs[2].value = (XtArgVal) 25;
  862.       numfree = COLORLESSPIXELS+25;
  863. #endif
  864.   } else {
  865. #ifdef USE_COLORS
  866.       mainargs[1].value = (XtArgVal) TRUE;
  867.       mainargs[2].value = (XtArgVal) 64;
  868.       numfree = NECESSARYPIXELS+64;
  869. #else
  870.       mainargs[1].value = (XtArgVal) FALSE;
  871.       mainargs[2].value = (XtArgVal) 64;
  872.       numfree = COLORLESSPIXELS+64;
  873. #endif
  874.   }
  875.  
  876.   realfree = createCmap(numfree, xwa.colormap, bestvip->visual);
  877.   XFree((char *) vip);
  878.  
  879.   mainargs[0].value = (XtArgVal) cmap;
  880.   if (realfree != numfree)
  881.     if (mainargs[1].value == (XtArgVal) TRUE)
  882.       mainargs[2].value = (XtArgVal) realfree-NECESSARYPIXELS;
  883.     else
  884.       mainargs[2].value = (XtArgVal) realfree-COLORLESSPIXELS;
  885.  
  886.   if (mainargs[2].value <= 0) {
  887.     fprintf(stderr, "Sorry, you don't have enough colormap cells.\n");
  888.     exit(1);
  889.   }
  890.  
  891.   XtUnmanageChild(dialog);
  892.   cpick = XtCreateManagedWidget(argv[0], cpickWidgetClass,
  893.                 toplevel, mainargs, XtNumber(mainargs));
  894.   XtAddCallback(cpick, XmNselectProc, (XtCallbackProc) doSelect, NULL);
  895.   XtAddCallback(cpick, XmNokProc, (XtCallbackProc) doOk, NULL);
  896.   XtAddCallback(cpick, XmNhelpProc, (XtCallbackProc) doHelp, NULL);
  897.   XtAddCallback(cpick, XmNchangeProc, (XtCallbackProc) doChange, NULL);
  898.   XtAddCallback(cpick, XmNrestoreProc, (XtCallbackProc) doRestore, NULL);
  899.  
  900.   cw = getD(cpick, XmNwidth);
  901.   ch = getD(cpick, XmNheight);
  902.   XGetWindowAttributes(XtDisplay(cpick),
  903.                XDefaultRootWindow(XtDisplay(cpick)), &xwa);
  904.   x = choose_x-(Position) (cw/2);
  905.   y = choose_y-(Position) (ch/2);
  906.   if (x < 0) {
  907.     x = 0;
  908.   } else if (x > xwa.width-cw) {
  909.     x = xwa.width-cw;
  910.   }
  911.   if (y < 0) {
  912.     y = 0;
  913.   } else if (y > xwa.height-ch) {
  914.     y = xwa.height-ch;
  915.   }
  916.  
  917.   XtMoveWidget(realtop, x, y);
  918.   XtRealizeWidget(realtop);
  919.   XtUnmapWidget(cpick);
  920.  
  921.   glevel = XmCreateForm(toplevel, "selectForm", gargs, XtNumber(gargs));
  922.   XtAddEventHandler(glevel, ExposureMask, TRUE,
  923.             (XtEventHandler) exposeHandler, NULL);
  924.   XtAddEventHandler(glevel, StructureNotifyMask, TRUE,
  925.             (XtEventHandler) resizeHandler, NULL);
  926.   XtManageChild(glevel);
  927.   doExpose();
  928.  
  929.   XSetWindowColormap(XtDisplay(realtop), XtWindow(realtop), cmap);
  930.   XSetWindowColormap(XtDisplay(toplevel), XtWindow(toplevel), cmap);
  931.   XSetWindowColormap(XtDisplay(cpick), XtWindow(cpick), cmap);
  932.   XSetWindowColormap(XtDisplay(cpick), XtWindow(XtParent(dialog)), cmap);
  933.  
  934.   XtMainLoop();
  935. }
  936.